#include <cstdio>
#include <cstdlib>
//#include <tchar.h>

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/video/video.hpp"
#include <opencv2/gpu/gpu.hpp>

#include <cstring>

using namespace std;
using namespace cv;


#include "VideoRead.h"

#include "FeatureComputer.h"

#include "Classifier.h"

#include "Bagging.h"

#include "ClassifierRank.h"



#include "Interface.h"


static void getLabelMask( Mat & res, Mat & mask , Size size, int bound_setting)
{
	int _rows = size.height;
	int _cols = size.width;

	int _sz = (_rows - 2* bound_setting) * (_cols - 2* bound_setting);

	if(_sz != (int) res.rows)
	{
		cout << "size unmatch while get label mask" << endl;
		return;
	}

	mask = Mat::zeros( _rows, _cols, CV_8U);

	vector<KeyPoint> keypts;

	{
		DenseFeatureDetector dfd;

		float initFeatureScale = 1.f;		// inital size
		int featureScaleLevels = 1;		// one level
		float featureScaleMul = 1.00f;	// multiplier (ignored if only one level)
		int train_initXyStep = 1;		// space between pixels for training (must be 1)

		dfd = DenseFeatureDetector(initFeatureScale,featureScaleLevels,featureScaleMul,train_initXyStep,bound_setting,true,false);

		dfd.detect(mask,keypts);
	}

	cout << "kp size " << keypts.size() << " res size " << res.rows << endl;
	
	for(int i = 0;i< (int)keypts.size();i++)
	{
		int r = int(floor(keypts[i].pt.y+.5));
		int c = int(floor(keypts[i].pt.x+.5));
		mask.at<unsigned char>(r,c) = (unsigned char)min( 255.0f, res.at<float>(i,0) * 255.0f);
	}
}

int main(int argc, char * const argv[])
{
	//testJumpReadandTrain();

	//testJumpRead();

	bool SAVE_IN_DIFFERENT_NAME = true;


	LcInterface my_setting;

	if(argc==1)
	{
		char *const setting_string[] ={ "","-b","-v","l","-t","GOPR2384_cab","-s", "150", "-e", "5300", "-r","50","-p","GOPR2384_cab","-f","./../../_FGS/","-h","-g","5"};

		//char *const setting_string[] ={ "","-a","-v","l","-t","GOPR2384_cab","-s", "175", "-e", "500", "-r","25","-p","GOPR2384_cab","-f","./../../_FGS/","-g","5","-j"};

		//char *const setting_string[] ={ "","-b","-v","l","-t","P_02","-s", "2000", "-e", "10000", "-r","1000","-p","P_02","-f","./../../_FGS/","-g","5","-j","-y",".jpg","-k","2","-h"};

		//char *const setting_string[] ={ "","-b","-v","lb","-t","GOPR2382_cab","-s", "175", "-e", "11150", "-r","25","-p","GOPR2384_cab","-f","./../../_FGS/"};

		//char *const setting_string[] ={ "","-b","-v","lb","-t","GOPR2382_cab","-s", "150", "-e", "5300", "-r","50","-p","GOPR2382_cab","-f","./../../_FGS/"};

		my_setting.input( 18 + 1 ,setting_string);
	}
	else my_setting.input( argc, argv);

	ClassifierRank my_crank;
	//Kmeans my_crank;

	LcVideoRead * my_reader = my_setting.getTrainVideop();

	my_crank.setReader( my_reader);

	my_crank.setFeatureCode( my_setting.feature_code_string.c_str() );

	my_crank.setClassifier( my_setting.getClassifier() );

	my_crank.IF_KMEAN = my_setting.IF_KMEAN;	

	//my_crank.trainPreFrame();

	if(my_setting.IF_TEST)
	{
		LocalSensitiveBagging crank_bagging;

		crank_bagging.setFeatureCode(my_setting.feature_code_string.c_str());

		crank_bagging.setReader( my_reader );

		{
			string saving_name = my_reader->root + "classifier_output/crank/crank_";

			if(SAVE_IN_DIFFERENT_NAME)
				saving_name = saving_name + "temp_" + my_setting.addition_str;

			crank_bagging.load( saving_name.c_str() );
		}

		LcVideoRead * test_video = my_setting.getTestVideop();

		cout << test_video->video_name << endl;

		LcGlobalExtractor * global_extractor
			= my_setting.my_global_extractor;		


		vector< LcValidator > validator_array;

		crank_bagging.knn = 70;



		if(my_setting.SAVE_LIKELI)
		{

			LcFeatureExtractor my_extractor;
			my_extractor.set_extractor( my_setting.feature_code_string.c_str() );

			string save_name_prefix = my_setting.test_video_name;

			test_video->reset();

			for(int i = 0 ; i < 1000000; i++)
			{
				Mat frm;
				int statu = test_video->readNext( frm );
				if(statu) break;
				Mat desc;
				my_extractor.work( frm ,desc);

				Mat _res,res;
				Mat empty_lab = Mat::Mat();

				Mat hist;

				global_extractor->work( frm , hist);

				crank_bagging.predict( desc, _res, empty_lab, hist);

				getLabelMask(_res, res, frm.size(), my_extractor.bound_setting);


				char fname[400];
				sprintf( fname , "./save_img/%s_likeli_%d.jpg", save_name_prefix.c_str() , i);
				imwrite(fname , frm);
				sprintf( fname , "./save_img/%s_src_%d.jpg", save_name_prefix.c_str() , i);
				imwrite(fname, res);

			}
		}
		else
		{

			LcValidator validator = crank_bagging.predict( *test_video, *global_extractor,validator_array);

			{
				string report_name;
				if(my_crank.IF_KMEAN)
					report_name = "./report/kmean_report_";
				else
					report_name = "./report/crank_report_";
				report_name = report_name + my_setting.train_video_name + "_on_"
					+ my_setting.test_video_name + "_v_" + my_setting.feature_code_string 
					+ my_setting.addition_str + ".txt";

				FILE * fout = fopen( report_name.c_str(),"w");

					for(int i = 0 ; i < (int) validator_array.size() ; i++)
					{
						fprintf(fout,"%f\t%f\t%f\t%f\t%f\n", validator_array[i].getF1(),
							validator_array[i].tp,validator_array[i].fp,validator_array[i].fn,validator_array[i].tn);
						printf("%f\t%f\t%f\t%f\t%f\n", validator_array[i].getF1(),
							validator_array[i].tp,validator_array[i].fp,validator_array[i].fn,validator_array[i].tn);

					}

					fprintf(fout,"%f\t%f\t%f\t%f\t%f\n", validator.getF1(),
						validator.tp,validator.fp,validator.fn,validator.tn);

				fclose(fout);
			}		
		}

	}

	if(my_setting.IF_TRAIN)
	{

		LcGlobalExtractor * global_extractor
			= my_setting.my_global_extractor;

		my_crank.setGlobalExtractor( global_extractor);

		if(my_setting.IF_TRAIN_PER_FRAME)
		{
			my_crank.trainPreFrame();

			my_crank.crossFrameTest();
		}

		//my_crank.classifier_affine_weight = my_setting.classifier_affine_weight;

		my_crank.val = my_setting.val;
		my_crank.beta = my_setting.beta;
		my_crank.cluster_n = my_setting.cluster_n;

		my_crank.cluster();

		int n_classifier; int instance_limit;

		{
			FILE * fid = fopen("bagging_config.txt","r");
			fscanf(fid, "%d%d",&n_classifier, &instance_limit);
			fclose(fid);
		}

		LocalSensitiveBagging crank_bagging;

		crank_bagging.setFeatureCode(my_setting.feature_code_string.c_str());

		crank_bagging.set( my_crank, n_classifier, instance_limit);

		crank_bagging.train();


		{
			string saving_name = my_reader->root + "classifier_output/crank/crank_";
			

			if(SAVE_IN_DIFFERENT_NAME)
				saving_name = saving_name + "temp_" + my_setting.addition_str;

			crank_bagging.save( saving_name.c_str() );
		}


	}

	//{
	//	my_reader.root = "./../../_FGS/";
	//	my_reader.video_name = "GOPR2384_cab";
	//	my_reader.f_start = 175;
	//	my_reader.f_end = 11150;
	//	my_reader.f_rate = 25;

	//	my_reader.veb = 1;

	//	my_crank.setReader( &my_reader);
	//}

	//LcFeatureExtractor my_extractor;

	//string feature_code = "l"; // "robvltdmchsug"

	//{
	//	my_crank.setFeatureCode( feature_code.c_str() );
	//}

	//LcRandomTrees my_classifier;

	//{
	//	my_classifier.veb = 1;
	//	my_crank.setClassifier( &my_classifier);
	//}

	//if(0){
	//	my_crank.cluster();

	//	LocalSensitiveBagging crank_bagging;

	//	crank_bagging.setFeatureCode("l");

	//	crank_bagging.set( my_crank, 1, 500000);

	//	crank_bagging.train();

	//	{
	//		string saving_name = my_reader.root + "classifier_output/crank/";
	//		crank_bagging.save( saving_name.c_str() );
	//	}
	//}
	//else
	//{
	//	LocalSensitiveBagging crank_bagging;

	//	crank_bagging.setFeatureCode("l");

	//	crank_bagging.setReader( &my_reader);

	//	{
	//		string saving_name = my_reader.root + "classifier_output/crank/";
	//		crank_bagging.load( saving_name.c_str() );
	//	}
	//}

	//system("pause");
}